import { JXDef } from '../../../conventions/JXCommon';
import { INVALID_VALUE_ZERO, OBJECT_COPY } from '../../../Core/CoreDefine';
import { MapWrap, NewFillArray } from '../../../Core/FrameEx/ES5Ex';
import GParam from '../../../Core/GEvent/GParam';
import { GRunTime } from "../../../Core/Manager/DataPool";
import MathEx from '../../../Core/Math/MathEx';
import { EQUIP_PART, HEROBUFF, HEROCHIPINFO, ITEM_TYPE, PART_PROPTS } from '../../Common/Define';
import { JXLocales } from '../../Common/Zh';
import GameMgr from "../../Logic/GameMgr";
import { JXIdGenerater } from '../../Views/JXBattle/JXBattleUtility';
import { INVALID_VALUE, PRIORITY_DATA } from './../../../Core/CoreDefine';
import { GCtrl } from './../../../Core/GCtrl';
import { CMsg } from './../../Common/Define';
import { REquireItem } from './RunRaw/RItemAttach';

const { ccclass } = cc._decorator;
@ccclass
export class RHeroData extends GRunTime {
	private _heroDatas: MapWrap<number, IHeroData> = new MapWrap<number, IHeroData>();
	private _heroEqData: MapWrap<number, REquireItem[]> = new MapWrap<number, REquireItem[]>();
	/** ID生成器 */
	public insIdGentor: JXIdGenerater;
	public get heroDatas(): MapWrap<number, IHeroData> {
		return this._heroDatas;
	}
	/**所有上阵的英雄*/
	private _heroIdsInBattle: number[] = [];

	public set heroIdsInBattle(v) {
		this._heroIdsInBattle = v;
		GameMgr.lUserData.heroInBattle = v;
	}

	public get heroIdsInBattle(): number[] {
		return this._heroIdsInBattle
	}

	private _tryHeroData: SHeroTryDataRaw = null;
	public get tryHeroData() {
		return this._tryHeroData
	}
	public set tryHeroData(v: SHeroTryDataRaw) {
		this._tryHeroData = v;
	}

	private _openBook: boolean = false;
	public get openBook() {
		return this._openBook;
	}
	public set openBook(v: boolean) {
		this._openBook = v;
	}
	public onInit() {
		this.insIdGentor = new JXIdGenerater('Hero');
		this._heroIdsInBattle = []
		this._heroIdsInBattle.push(...GameMgr.lUserData.heroInBattle);
		this.initEvent();
		this.inAllHeroData();
	}

	public save() {
		GameMgr.lHeroData.save(this.heroDatas);
	}

	/**确定是否为空队伍 */
	public checkInNoHero(): boolean {
		let isNoHero = true;
		for (let i = 0; i < this.heroIdsInBattle.length; i++) {
			if (this._heroIdsInBattle[i] != INVALID_VALUE) {
				isNoHero = false;
				break;
			}
		}
		return isNoHero;
	}

	/** */
	public checkBattleTeamisFull() {
		let isFull = true;
		for (let i = 0; i < this.heroIdsInBattle.length; i++) {
			if (this._heroIdsInBattle[i] === INVALID_VALUE) {
				isFull = false;
				break;
			}
		}
		return isFull
	}


	/**创建战报数据 */
	public createRespWithRealData(levelRaw: STowerDataRaw | SStoryDataRaw): BattleInfo<IMonsterBtl, IMonsterBtl> {
		let btlReport = {} as BattleInfo<IMonsterBtl, IMonsterBtl>;
		if (!levelRaw) {
			cc.error("关卡数据不存在");
			return;
		}
		let arr = [];
		let monId = [];
		for (let i = 0; i < levelRaw.monsterTeam.length; i++) {
			let team = levelRaw.monsterTeam[i];
			let idArr = [];
			for (let j = 0; j < team.length; j++) {
				let teamId = team[j];
				let monIdArr = [];
				let heroArr = []
				if (teamId != INVALID_VALUE) {
					let teamHeros = GameMgr.npcTeamData.getRaw<SNpcTeamDataRaw>(teamId);
					for (let e = 0; e < teamHeros.team.length; e++) {
						let monsterId = teamHeros.team[e];
						let monsterRaw = GameMgr.unitData.getRaw<SUnitDataRaw>(monsterId);
						let monster = null;
						if (monsterRaw) {
							monster = this.createHeroData(monsterRaw.unitId);
						}
						if (monster) {
							monster.unitId = monsterId;
							monster.heroId = this.insIdGentor.getNewId();
							monster.propts = OBJECT_COPY(monsterRaw.alter);
							monIdArr.push(monster.heroId);
						} else {
							monIdArr.push("-1");
						}
						heroArr.push(monster)
					}
				}
				idArr.push(monIdArr)
				arr.push(...heroArr)
			}
			monId.push(idArr)
		}
		btlReport.atker = this.getMonInfo(arr);
		btlReport.atker.ext = monId;

		let defHeros: IHeroData[] = [];
		this._heroIdsInBattle.forEach(id => {
			let hero = this._heroDatas.get(id);
			defHeros.push(hero)
		})
		if (this._tryHeroData) {
			let raw = GameMgr.heroData.getRaw<SHeroDataRaw>(this._tryHeroData.heroId);
			let tryHeroData = this.createHeroData(this._tryHeroData.heroId);
			let ItryHeroData: IHeroData = tryHeroData;
			ItryHeroData.exp = 0;
			ItryHeroData.skillIds = raw.skill;
			ItryHeroData.star = 5;
			ItryHeroData.trait = 5;
			ItryHeroData.propts.map((value, index) => {
				if (index <= PART_PROPTS.XueLiang) {
					ItryHeroData.propts[index] = tryHeroData.propts[index] * (this._tryHeroData.up + 1);
				}
			})
			let nullIndex = defHeros.indexOf(null);
			if (nullIndex != INVALID_VALUE) {
				defHeros[nullIndex] = ItryHeroData;
			} else {
				let index = MathEx.random(0, defHeros.length - 1);
				defHeros[index] = ItryHeroData;
			}
			this._tryHeroData = null;
		}
		btlReport.defer = this.getMonInfo(defHeros);
		return btlReport;
	}

	protected getMonInfo(heros: IHeroData[]): IMonsterBtl {
		let team = {
			heroIds: [],
			tableIds: [],
			partnerData: [],
		}
		heros.forEach((hero) => {
			let heroId = null
			if (hero && hero.heroId) {
				heroId = hero.heroId;
			} else {
				heroId = this.insIdGentor.getNewId();
			}

			team.heroIds.push(hero ? heroId : "-1");
			team.tableIds.push(hero ? hero.tableId : INVALID_VALUE)
			if (hero) {
				let btlAtk: IHeroBtlData = OBJECT_COPY(hero);
				btlAtk.heroId = heroId;
				btlAtk.curHp = hero.propts[PART_PROPTS.XueLiang];
				btlAtk.maxHp = hero.propts[PART_PROPTS.XueLiang];
				team.partnerData.push(btlAtk);
				// let passive = [];
				// let initiative = [];
				// hero.skillIds.forEach((v, index) => {
				// 	if (index == 1 || index == 3) {
				// 		passive.push(v)
				// 	} else {
				// 		initiative.push(v)
				// 	}
				// })
				// hero.skillIds = [...passive, ...initiative];
			}
		})
		return team;
	}

	/**创建英雄数据 */
	public createHeroData(heroId: number | SHeroDataRaw, nickName?: string): IHeroBtlData {
		let hero: SHeroDataRaw = null;
		if (typeof heroId == "number") {
			hero = GameMgr.heroData.getRaw<SHeroDataRaw>(heroId)
		} else {
			hero = heroId;
		}
		if (!hero) {
			return null;
		}
		let heroData: IHeroBtlData = {
			tableId: hero.id,
			propts: hero.property,
			extendPropts: [],
			equips: [],
			skillIds: hero.skill,
			suitBuffIds: [],
			lv: 1,
			camp: hero.type,
			nickName: nickName ? nickName : hero.name,
			trait: hero.trait,
		}
		return heroData;
	}



	/**初始化所有的英雄数据 */
	protected inAllHeroData() {
		let heros = OBJECT_COPY<IHeroData[]>(GameMgr.lHeroData.getAllHeros());
		if (heros.length) {
			let defaultData: IHeroData = {
				exp: 0,
				tableId: 0,
				lv: 1,
				propts: [],
				equips: [],
				skillIds: [],
				suitBuffIds: [],
				camp: 1,
				trait: 1,
				star: 1,
			}

			heros.forEach((hero) => {
				this._heroDatas.set(hero.tableId, hero);
				for (const key in defaultData) {
					if (!Object.prototype.hasOwnProperty.call(hero, key)) {
						hero[key] = defaultData[key];
					}
				}
				this.updateHeroProp(hero)
			})

		}
		let data = GameMgr.heroData.getHeroTrue();
		data.forEach((hero) => {
			if (!hero.unlock && !this._heroDatas.has(hero.id)) {
				this.addHero(hero);
			}
		})
		this.save();
	}

	protected initEvent() {
		GCtrl.ES.on(CMsg.client.equip.onEquipPutOn, this, this.onEquipPutOn.bind(this), PRIORITY_DATA);
		GCtrl.ES.on(CMsg.client.equip.onEquipPutOff, this, this.onEquipPutOff.bind(this), PRIORITY_DATA);
		GCtrl.ES.on(CMsg.client.hero.onAddHero, this, this.onAddHero.bind(this), PRIORITY_DATA);
		GCtrl.ES.on(CMsg.client.hero.onHeroAddExp, this, this.onAddExp.bind(this), PRIORITY_DATA);
		GCtrl.ES.on(CMsg.client.hero.onSetSkill, this, this.setSkill.bind(this), PRIORITY_DATA);
		GCtrl.ES.on(CMsg.client.hero.onHeroAddStar, this, this.onHeroAddStar.bind(this), PRIORITY_DATA);
		GCtrl.ES.on(CMsg.client.hero.onHeroLvUp, this, this.onHeroUpLv.bind(this), PRIORITY_DATA);
		GCtrl.ES.on(CMsg.client.hero.onHeroBreach, this, this.onHeroBreach.bind(this), PRIORITY_DATA);

		GCtrl.ES.on(CMsg.client.hero.onAddSuit, this, this.suitBuff.bind(this), PRIORITY_DATA);
		GCtrl.ES.on(CMsg.client.hero.onGetHeroZhangLi, this, this.onGetHeroZhangLi.bind(this), PRIORITY_DATA);
	}

	/**计算属性*/
	protected onPropChange(hero: IHeroData) {
		let raw = GameMgr.heroData.getRaw<SHeroDataRaw>(hero.tableId);
		let lvRaw = GameMgr.lvData.getRaw<SLvDataRaw>(hero.lv);
		let starRaw = GameMgr.starLvData.getRaw<SStarLvDataRaw>(hero.star);
		var suitArr: number[] = NewFillArray(10, INVALID_VALUE_ZERO);
		hero.propts = OBJECT_COPY(raw.property);
		let arr: Array<Array<number>> = GameMgr.lUserData.getHeroBuff(hero.tableId);
		//vip英雄增益
		arr.forEach((v) => {
			raw.property[v[HEROBUFF.index]] += v[HEROBUFF.num];
		})

		let num = 0;//集齐套装拥有装备兵书数量
		let equipSuitArr: number[] = new Array<number>();//存储套装strID 判断是否重复穿戴了同装备id的装备兵书 导致套装集齐数量累加
		let arrSuit = new Array<number>();//集齐套装数量
		hero.suitBuffIds.forEach((v, index) => {
			equipSuitArr = [];
			let suit = GameMgr.suitData.getRaw<SSuitDataRaw>(v);
			num = 0;
			suitArr = NewFillArray(10, INVALID_VALUE_ZERO);
			suit.suit.forEach((s) => {
				hero.equips.forEach((equip, count) => {
					if (equip != "-1" && equip) {//装备id有的情况下
						let equipData = GameMgr.RBagData.getEquipDataById(equip);
						if (!equipData) {
							return;
						}
						if (s == equipData.equipId) {
							if (count >= 3) {
								if (equipSuitArr.length > 0) {
									equipSuitArr.forEach((v) => {
										if (v == equipData.equipId) {
											return;
										} else {
											num++;
											equipSuitArr.push(equipData.equipId);
										}
									})
								} else {
									num++;
									equipSuitArr.push(equipData.equipId);
								}
							} else {
								num++;
							}
						}
					}
				})
			})
			//几套装 集齐件数
			if (num > 0) {
				arrSuit.push(num);
			} else {
				hero.suitBuffIds.splice(index, 1);
			}

			if (index == hero.suitBuffIds.length - 1) {
				arrSuit.forEach((suit, index) => {
					let suitData = GameMgr.suitData.getRaw<SSuitDataRaw>(index + 1);
					// console.log('几套装 集齐件数', index);
					if (suit >= EQUIP_PART.WUQI + 1) {
						for (let j = 0; j < suitData.up2.length; j++) {
							suitArr[j] += suitData.up2[j];
						}
						// console.log('up2', suitArr);
					}

					if (suit >= EQUIP_PART.HEAD + 1) {
						for (let j = 0; j < suitData.up3.length; j++) {
							suitArr[j] += suitData.up3[j];
						}
						// console.log('up3', suitArr);

					}

					if (suit >= EQUIP_PART.BINGSHU1 + 1) {
						for (let j = 0; j < suitData.up4.length; j++) {
							suitArr[j] += suitData.up4[j];
						}
						// console.log('up4', suitArr);
					}

					if (suit >= EQUIP_PART.BINGSHU2 + 1) {
						for (let j = 0; j < suitData.up5.length; j++) {
							suitArr[j] += suitData.up5[j];
						}
						// console.log('up5', suitArr);
					}

					if (suit >= EQUIP_PART.BINGSHU3) {
						for (let j = 0; j < suitData.allUp.length; j++) {
							suitArr[j] += suitData.allUp[j];
						}
						// console.log('allUp', suitArr);
					}
				})
			}
		})

		if (GameMgr.lUserData.vipLv >= 1 && hero.tableId == 1001) {
			raw.property[0] += 500;
			// console.log('raw.property[0]', raw.property[0]);
		}
		for (let i = 0; i < hero.propts.length; i++) {
			hero.propts[i] = raw.property[i] + (raw.growValue[i] * (1 + lvRaw.grow + starRaw.grow)) + suitArr[i];
		}
	}

	/**计算装备属性*/
	protected onEquipChange(hero: IHeroData) {
		let equips = this._heroEqData.get(hero.tableId);
		for (let i = 0; i < hero.propts.length; i++) {
			for (let j = 0; j < equips.length; j++) {
				if (equips[j]) {
					hero.propts[i] += equips[j].propts.get(i)
				}
			}
		}
	}

	/**添加英雄 */
	protected onAddHero(_, id) {
		this.addHero(id)
	}

	/**添加经验 */
	protected onAddExp(_, param: GParam) {
		let info = param.get<HeroAddExp>();
		let hero = this._heroDatas.get(info.heroId);
		if (!hero) {
			cc.error("英雄添加经验失败：英雄不存在");
			return;
		}
		hero.exp += info.exp;
		this._heroDatas.set(hero.tableId, hero);
		this.save();
	}


	/**修改技能 */
	protected setSkill(_, param: GParam) {
		let info = param.get<HeroSetSkill>();
		let hero = this._heroDatas.get(info.heroId);
		if (!hero) {
			cc.error("英雄添加经验失败：英雄不存在");
			return;
		}
		hero.skillIds = info.skill;
		this.save();
	}

	/**修改套装buff */
	protected suitBuff(_, param: GParam) {
		// console.log("修改套装buff");
		let info = param.get<suitInfo>();
		let hero = this._heroDatas.get(info.IHeroData.tableId);
		if (!hero) {
			cc.error("英雄添加套装buff失败：英雄不存在");
			return;
		}
		let arr = hero.suitBuffIds;
		if (arr.length > 0) {
			let bool = false;
			hero.suitBuffIds.forEach((v) => {
				if (info.suit) {
					if (v == info.suit.id) {
						bool = true;
					}
					if (!bool) {
						arr.push(info.suit.id);
					}
				}
			})
		} else {
			if (info.suit) {
				arr.push(info.suit.id);
			}
		}
		hero.suitBuffIds = arr;

		this.save();
	}

	protected onHeroAddStar(_, id) {
		let hero = this._heroDatas.get(id);
		if (!hero) {
			cc.error("英雄升星失败：英雄不存在");
			return;
		}
		hero.star++;
		this.updateHeroProp(hero);
		this.heroDatas.set(hero.tableId, hero)
		this.save();
	}


	protected onHeroUpLv(_, id) {
		let hero = this._heroDatas.get(id);
		if (!hero) {
			cc.error("英雄升级失败：英雄不存在");
			return;
		}
		hero.lv++;
		this.updateHeroProp(hero);
		this.heroDatas.set(hero.tableId, hero)
		this.save();
	}

	/**卡级突破 */
	protected onHeroBreach(_, id) {
		let hero = this._heroDatas.get(id);
		if (!hero) {
			cc.error("英雄升级失败：英雄不存在");
			return;
		}
		hero.trait++;
		this.updateHeroProp(hero);
		this.heroDatas.set(hero.tableId, hero)
		this.save();
	}

	/**添加英雄 */
	protected addHero(heroId: number | SHeroDataRaw, isSave: boolean = true): IHeroData {
		let hero: SHeroDataRaw = null;
		if (typeof heroId == "number") {
			hero = GameMgr.heroData.getRaw<SHeroDataRaw>(heroId)
		} else {
			hero = heroId;
		}
		if (!hero) {
			return null;
		}
		if (this.hasOwnHero(hero.id)) {
			//重复获得得英雄分解碎片
			// console.log("重复获得得英雄分解碎片");
			let birthStar: number = GameMgr.heroData.getRaw<SHeroDataRaw>(hero.id).birthStar;
			let chips = null;
			let heroresolve: [] = GameMgr.systemConfig.value(JXDef.SYS_CONFIG_KEY.heroresolve);
			heroresolve.forEach((v: number[]) => {
				if (v[HEROCHIPINFO.HEROID] == hero.id) {
					chips = v[HEROCHIPINFO.HEROCHIPNUM];
					GCtrl.ES.emit(CMsg.client.bag.onBagItemChange, [[hero.id, ITEM_TYPE.PROP, chips]])
				}
			})
			// //单个星星碎片数
			// if (obj.lv > GameMgr.heroData.getRaw<SHeroDataRaw>(hero.id).star.length) {
			// 	obj.lv = GameMgr.heroData.getRaw<SHeroDataRaw>(hero.id).star.length;
			// }
			// for (let i = 0; i < obj.lv; i++) {
			// 	let count = null;
			// 	if (obj.lv - i > 1) {
			// 		count = GameMgr.heroData.getRaw<SHeroDataRaw>(hero.id).star[i] * 5;
			// 	} else {
			// 		count = GameMgr.heroData.getRaw<SHeroDataRaw>(hero.id).star[i] * obj.count;
			// 	}
			// 	chips += count;
			// }
			return null;
		} else {
			let hero1 = GameMgr.lUserData.heroNames(hero.id);
			GameMgr.sdkMgr.umaSetPoint(JXDef.umaPoint.FeatureCtrl, { msg: JXLocales.tower.hero + hero1 })
		}

		let heroData: IHeroData = {
			exp: 0,
			tableId: hero.id,
			propts: hero.property,
			equips: [],
			skillIds: [],
			suitBuffIds: [],
			lv: GameMgr.lvData.getLvMinByTrait(hero.trait),
			camp: hero.type,
			trait: hero.trait,
			star: hero.birthStar,
		}
		heroData.skillIds = GameMgr.skillData.getHeroUseSkill(heroData.tableId, heroData.lv);
		if (isSave) {
			this._heroDatas.set(heroData.tableId, heroData);
			this.updateHeroProp(heroData);
			this.save();
		}
		return heroData;
	}

	/**
	  * 修改对应的英雄数据 
	  */
	protected setHero(hero: IHeroData) {
		let heroData = this._heroDatas.get(hero.tableId)
		if (!heroData) return;
		this._heroDatas.set(hero.tableId, hero)
		this.save();
	}

	/**是否拥有英雄 */
	public hasOwnHero(heroId: number) {
		return this._heroDatas.has(heroId);
	}

	/**判断英雄是否上阵*/
	public checkHeroIsInBattle(heroId: number) {
		return this._heroIdsInBattle.indexOf(heroId) != INVALID_VALUE;
	}

	/**获取战斗中的英雄 */
	public getHeroInBattle() {
		return this._heroIdsInBattle;
	}

	/**获取对应的英雄数据 */
	public getHero(heroId: number): IHeroData {
		let hero = this._heroDatas.get(heroId);
		return OBJECT_COPY(hero);
	}

	/**获取所有英雄 */
	public getAllHeros() {
		return this._heroDatas;
	}

	/**通过类型取拥有英雄静态数据 */
	public getHaveHeros(type: number): { have: IHeroData[], notHave: SHeroDataRaw[] } {
		if (type != 0) {
			var data: SHeroDataRaw[] = GameMgr.heroData.getHeroByType(type);
		} else {
			var data: SHeroDataRaw[] = GameMgr.heroData.getHeroTrue();
		}
		let have: IHeroData[] = [];
		let noHave: SHeroDataRaw[] = [];
		data.forEach((value) => {
			if (this._heroDatas.has(value.id)) {
				have.push(this.heroDatas.get(value.id));
			} else {
				noHave.push(value);
			}
		})
		return { have, notHave: noHave };
	}

	/**获取当前职业最大等级 */
	public curHeroTypeMaxLv(type: number) {
		var maxLv: number = 1;
		var data: SHeroDataRaw[] = GameMgr.heroData.getHeroByType(type);
		data.forEach((value) => {
			this._heroDatas.forEach((v: IHeroData) => {
				if (this._heroDatas.has(value.id) && v.tableId == value.id) {
					if (maxLv < v.lv) {
						maxLv = v.lv;
					}
					// console.log('当前职业最大等级', maxLv);
				}
			})
		})
		return maxLv;
	}

	/**脱装 */
	protected onEquipPutOff(_, param: GParam) {
		let info = param.get<EquipPutInfo>();
		let hero = this.heroDatas.get(info.heroId);
		hero.equips[info.site] = "-1";
		this.heroDatas.set(info.heroId, hero)
		this.updateHeroProp(hero);
		this.save();
	}

	/**穿戴装备 */
	protected onEquipPutOn(_, param: GParam) {
		let info = param.get<EquipPutInfo>();
		let hero = this.heroDatas.get(info.heroId);
		hero.equips[info.site] = info.equipId;
		this.heroDatas.set(info.heroId, hero)
		this.updateHeroProp(hero);
		this.save();
	}

	/**获取英雄战力 */
	protected onGetHeroZhangLi(_, param: GParam) {
		let info = param.get<HeroZhangLi>();
		let hero = this.heroDatas.get(info.heroId);
		this.updateHeroProp(hero);
		this.save();
	}

	/**更新玩家装备 */
	protected updateHeroProp(data: IHeroData) {
		if (!data.equips.length) {
			this._heroEqData.set(data.tableId, [])
		}
		for (let i = 0; i < data.equips.length; i++) {
			let array = this._heroEqData.get(data.tableId);
			if (!array) {
				array = [];
			}
			if (!data.equips[i] || data.equips[i] == "-1") {
				array[i] = null;
			} else {
				let item = GameMgr.RBagData.getEquipDataById(data.equips[i]);
				array[i] = item;
			}
			this._heroEqData.set(data.tableId, array)
		}
		this.onPropChange(data);
		this.onEquipChange(data);
	}
}